package preprocessor.absorption;

import java.util.HashSet;

import utils.exception.ConceptException;

import entities.InclusionAxiom;
import entities.concept.AndConcept;
import entities.concept.Concept;
import entities.concept.NotConcept;
import entities.concept.OrConcept;
import entities.concept.PConcept;
import entities.vocabulary.KBVocabulary;
import kb.TBox;

public class BinaryAbsorption implements Absorption {
	TBox tbox;
	
	public BinaryAbsorption (TBox tb){
		this.tbox = tb;
	}
	
	public boolean absorb() {
		// TODO Auto-generated method stub
		boolean suc = true;
		if(this.tbox.getTg().size()>0){
			// try to absorb each GCI
			for(Concept c:this.tbox.getTg().keySet()){
				InclusionAxiom ax = new InclusionAxiom(c, this.tbox.getTg().get(c));
				suc = suc && absorbAxiom(ax);
			}
		}
		return suc;
	}
	
	/**
	 * Absorb a single axiom for A /\ B -> C
	 * @param ax
	 * @return
	 */
	public boolean absorbAxiom(InclusionAxiom ax){
		boolean abs = false;
		Concept lhs = ax.getLHS();
		if(lhs.isBinarySimple()){
			// a and b -> c
			AndConcept ac = (AndConcept)lhs;
			try{
				this.tbox.insertTb(ac.getConceptSet(), ax.getRHS());
				abs = true;
			}catch(Exception e){
				e.printStackTrace();
			}
		}else{
			//convert axiom into top->{a set of disjuncts}
			HashSet<Concept> ors = new HashSet<Concept>();
			ors.add(new NotConcept(lhs));
			ors.add(ax.getRHS());
			OrConcept gen = new OrConcept(ors);
			abs = absorbAxiom(Concept.reduceToDisjuncts(gen));
		}
		
		return abs;
	
	}
	
	//if the axiom is given as a set of disjuncts, only consider ~a, ~b, etc.
	public boolean absorbAxiom(HashSet<Concept> ax){
		boolean abs = false;
		HashSet<Concept> todo = new HashSet<Concept>();
		HashSet<Concept> remain = new HashSet<Concept>();
		remain.addAll(ax);
		for(Concept c:ax){
			if(c.isSimpleNot()){
				NotConcept nc = (NotConcept)c;
				remain.remove(c);
				todo.add( nc.getConcept());
				if(todo.size()==2){
					break;
				}
			}
		}
		if(todo.size()!=2){
			return false;
		}
		PConcept fresh = PConcept.newFreshPConcept();
		remain.add(new NotConcept(fresh));
		try {
			this.tbox.insertTb(todo, fresh);
			abs = true;
		} catch (ConceptException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		//add the new axiom back
		this.tbox.saveGeneratedGCIs(KBVocabulary.CONCEPT_TOP, new OrConcept(remain));
		return abs;
	}
	

}
